1
2
3
4 package joeq.Bootstrap;
5
6 import java.util.HashSet;
7 import java.util.Iterator;
8 import java.util.LinkedHashSet;
9 import java.util.LinkedList;
10 import java.util.List;
11 import java.util.Set;
12 import joeq.Class.PrimordialClassLoader;
13 import joeq.Class.jq_Array;
14 import joeq.Class.jq_Class;
15 import joeq.Class.jq_ClassInitializer;
16 import joeq.Class.jq_Field;
17 import joeq.Class.jq_FieldVisitor;
18 import joeq.Class.jq_Initializer;
19 import joeq.Class.jq_InstanceField;
20 import joeq.Class.jq_InstanceMethod;
21 import joeq.Class.jq_Member;
22 import joeq.Class.jq_Method;
23 import joeq.Class.jq_MethodVisitor;
24 import joeq.Class.jq_Primitive;
25 import joeq.Class.jq_Reference;
26 import joeq.Class.jq_StaticField;
27 import joeq.Class.jq_StaticMethod;
28 import joeq.Class.jq_Type;
29 import joeq.Class.jq_TypeVisitor;
30 import joeq.Memory.CodeAddress;
31 import joeq.Memory.HeapAddress;
32 import joeq.Memory.StackAddress;
33 import joeq.Runtime.ExceptionDeliverer;
34 import joeq.Runtime.Reflection;
35 import joeq.Runtime.SystemInterface;
36 import joeq.Runtime.Unsafe;
37 import jwutil.collections.IdentityHashCodeWrapper;
38 import jwutil.util.Assert;
39
40 /***
41 * BootstrapRootSet
42 *
43 * @author John Whaley <jwhaley@alum.mit.edu>
44 * @version $Id: BootstrapRootSet.java 1941 2004-09-30 03:37:06Z joewhaley $
45 */
46 public class BootstrapRootSet {
47
48 public static
49 public static final java.io.PrintStream out = System.out;
50
51 protected final Set
52 protected final Set
53 protected final Set
54 protected final Set
55
56 protected final LinkedHashSet
57
58 protected List
59 protected List
60 protected List
61 protected List
62
63 public boolean AddAllFields;
64
65 /*** Creates new BootstrapRootSet */
66 public BootstrapRootSet(boolean addall) {
67 this.instantiatedTypes = new HashSet();
68 this.necessaryTypes = new HashSet();
69 this.necessaryFields = new HashSet();
70 this.necessaryMethods = new HashSet();
71 this.visitedObjects = new LinkedHashSet();
72 this.AddAllFields = addall;
73 }
74
75 public Set
76 public Set
77 public Set
78 public Set
79
80 public void registerInstantiatedTypeListener(jq_TypeVisitor tv) {
81 if (instantiatedTypesListeners == null)
82 instantiatedTypesListeners = new LinkedList();
83 instantiatedTypesListeners.add(tv);
84 }
85 public void unregisterInstantiatedTypeListener(jq_TypeVisitor tv) {
86 instantiatedTypesListeners.remove(tv);
87 }
88 public void registerNecessaryTypeListener(jq_TypeVisitor tv) {
89 if (necessaryTypesListeners == null)
90 necessaryTypesListeners = new LinkedList();
91 necessaryTypesListeners.add(tv);
92 }
93 public void unregisterNecessaryTypeListener(jq_TypeVisitor tv) {
94 necessaryTypesListeners.remove(tv);
95 }
96 public void registerNecessaryFieldListener(jq_FieldVisitor tv) {
97 if (necessaryFieldsListeners == null)
98 necessaryFieldsListeners = new LinkedList();
99 necessaryFieldsListeners.add(tv);
100 }
101 public void unregisterNecessaryFieldListener(jq_FieldVisitor tv) {
102 necessaryFieldsListeners.remove(tv);
103 }
104 public void registerNecessaryMethodListener(jq_MethodVisitor tv) {
105 if (necessaryMethodsListeners == null)
106 necessaryMethodsListeners = new LinkedList();
107 necessaryMethodsListeners.add(tv);
108 }
109 public void unregisterNecessaryMethodListener(jq_MethodVisitor tv) {
110 necessaryMethodsListeners.remove(tv);
111 }
112
113 public boolean addInstantiatedType(jq_Type t) {
114 Assert._assert(t != null);
115 addNecessaryType(t);
116 boolean b = instantiatedTypes.add(t);
117 if (b) {
118 if (TRACE) out.println("New instantiated type: "+t);
119 if (instantiatedTypesListeners != null) {
120 for (Iterator i=instantiatedTypesListeners.iterator(); i.hasNext(); ) {
121 jq_TypeVisitor tv = (jq_TypeVisitor)i.next();
122 t.accept(tv);
123 }
124 }
125 }
126 return b;
127 }
128
129 public jq_Type addNecessaryType(String desc) {
130 String className = desc.substring(1, desc.length()-1).replace('/', '.');
131 try {
132
133 Class.forName(className);
134 jq_Type t = null;
135 try {
136 t = PrimordialClassLoader.loader.getOrCreateBSType(desc);
137 t.load();
138 addNecessaryType(t);
139 return t;
140 } catch (NoClassDefFoundError x) {
141 System.out.println("Note: Cannot load class "+t+" present in host Jvm");
142 PrimordialClassLoader.unloadType(PrimordialClassLoader.loader, t);
143 }
144 } catch (ClassNotFoundException x) { }
145 return null;
146 }
147
148 public boolean addNecessaryType(jq_Type t) {
149 if (t == null) return false;
150 t.prepare();
151 boolean b = necessaryTypes.add(t);
152 if (b) {
153 if (TRACE) out.println("New necessary type: "+t);
154 if (necessaryTypesListeners != null) {
155 for (Iterator i=necessaryTypesListeners.iterator(); i.hasNext(); ) {
156 jq_TypeVisitor tv = (jq_TypeVisitor)i.next();
157 t.accept(tv);
158 }
159 }
160 if (t instanceof jq_Class) {
161 jq_Class klass = (jq_Class)t;
162 if (AddAllFields) {
163 jq_StaticField[] sfs = klass.getDeclaredStaticFields();
164 for (int i=0; i<sfs.length; ++i) {
165 addNecessaryField(sfs[i]);
166 }
167 }
168
169 addNecessaryType(klass.getSuperclass());
170 }
171 }
172 return b;
173 }
174
175 public jq_StaticField addNecessaryStaticField(jq_Class c, String name, String desc) {
176 if (c == null) return null;
177 jq_StaticField f = c.getOrCreateStaticField(name, desc);
178 addNecessaryField(f);
179 return f;
180 }
181
182 public jq_InstanceField addNecessaryInstanceField(jq_Class c, String name, String desc) {
183 if (c == null) return null;
184 jq_InstanceField f = c.getOrCreateInstanceField(name, desc);
185 addNecessaryField(f);
186 return f;
187 }
188
189 public boolean addNecessaryField(jq_Field t) {
190 addNecessaryType(t.getDeclaringClass());
191 boolean b = necessaryFields.add(t);
192 if (b) {
193 if (TRACE) out.println("New necessary field: "+t);
194 if (necessaryFieldsListeners != null) {
195 for (Iterator i=necessaryFieldsListeners.iterator(); i.hasNext(); ) {
196 jq_FieldVisitor tv = (jq_FieldVisitor)i.next();
197 t.accept(tv);
198 }
199 }
200 }
201 return b;
202 }
203
204 public jq_StaticMethod addNecessaryStaticMethod(jq_Class c, String name, String desc) {
205 if (c == null) return null;
206 jq_StaticMethod f = c.getOrCreateStaticMethod(name, desc);
207 addNecessaryMethod(f);
208 return f;
209 }
210
211 public jq_InstanceMethod addNecessaryInstanceMethod(jq_Class c, String name, String desc) {
212 if (c == null) return null;
213 jq_InstanceMethod f = c.getOrCreateInstanceMethod(name, desc);
214 addNecessaryMethod(f);
215 return f;
216 }
217
218 public boolean addNecessaryMethod(jq_Method t) {
219 addNecessaryType(t.getDeclaringClass());
220 boolean b = necessaryMethods.add(t);
221 if (b) {
222 if (TRACE) out.println("New necessary method: "+t);
223 if (necessaryMethodsListeners != null) {
224 for (Iterator i=necessaryMethodsListeners.iterator(); i.hasNext(); ) {
225 jq_MethodVisitor tv = (jq_MethodVisitor)i.next();
226 t.accept(tv);
227 }
228 }
229 }
230 return b;
231 }
232
233 public void addDefaultRoots() {
234 jq_Class c;
235 jq_StaticMethod s_m; jq_InstanceMethod i_m;
236
237
238
239 addNecessaryType(jq_Class._class);
240 addNecessaryType(jq_Primitive._class);
241 addNecessaryType(jq_Array._class);
242 addNecessaryType(jq_InstanceField._class);
243 addNecessaryType(jq_StaticField._class);
244 addNecessaryType(jq_InstanceMethod._class);
245 addNecessaryType(jq_StaticMethod._class);
246 addNecessaryType(jq_Initializer._class);
247 addNecessaryType(jq_ClassInitializer._class);
248 addNecessaryType(CodeAddress._class);
249 addNecessaryType(HeapAddress._class);
250 addNecessaryType(StackAddress._class);
251 addNecessaryField(jq_Reference._vtable);
252
253
254 SystemInterface._class.load();
255 jq_StaticField[] sfs = SystemInterface._class.getDeclaredStaticFields();
256 for (int i=0; i<sfs.length; ++i) {
257 addNecessaryField(sfs[i]);
258 }
259
260
261 Unsafe._class.load();
262 jq_StaticMethod[] sms = Unsafe._class.getDeclaredStaticMethods();
263 for (int i=0; i<sms.length; ++i) {
264 if (sms[i] instanceof jq_ClassInitializer) continue;
265 addNecessaryMethod(sms[i]);
266 }
267
268
269
270 addNecessaryType(joeq.Allocator.SimpleAllocator._class);
271 addNecessaryType(PrimordialClassLoader.loader.getOrCreateBSType("Ljoeq/Allocator/RuntimeCodeAllocator;"));
272
273
274 c = PrimordialClassLoader.getJavaLangSystem();
275 addNecessaryStaticField(c, "in", "Ljava/io/InputStream;");
276 addNecessaryStaticField(c, "out", "Ljava/io/PrintStream;");
277 addNecessaryStaticField(c, "err", "Ljava/io/PrintStream;");
278
279
280 addNecessaryStaticMethod(c, "initializeSystemClass", "()V");
281
282
283 c = (jq_Class)Reflection.getJQType(sun.io.CharToByteConverter.getDefault().getClass());
284 addNecessaryInstanceMethod(c, "<init>", "()V");
285
286
287 c = (jq_Class)Reflection.getJQType(sun.io.ByteToCharConverter.getDefault().getClass());
288 addNecessaryInstanceMethod(c, "<init>", "()V");
289
290
291 s_m = ExceptionDeliverer._trap_handler;
292 addNecessaryMethod(s_m);
293
294
295 i_m = jq_Method._compile;
296 addNecessaryMethod(i_m);
297
298
299 if (false) {
300 s_m = ExceptionDeliverer._debug_trap_handler;
301 addNecessaryMethod(s_m);
302 }
303
304
305 addNecessaryMethod(joeq.Scheduler.jq_NativeThread._nativeThreadEntry);
306
307 addNecessaryMethod(joeq.Scheduler.jq_NativeThread._threadSwitch);
308
309 addNecessaryMethod(joeq.Scheduler.jq_NativeThread._ctrl_break_handler);
310
311 addNecessaryMethod(joeq.Scheduler.jq_InterrupterThread._run);
312
313
314 addNecessaryType(joeq.Assembler.Heap2HeapReference._class);
315
316 try {
317
318 c = (jq_Class)Reflection.getJQType(sun.io.ByteToCharConverter.getConverter("ISO-8859-1").getClass());
319 addNecessaryInstanceMethod(c, "<init>", "()V");
320
321 c = (jq_Class)Reflection.getJQType(sun.io.CharToByteConverter.getConverter("ISO-8859-1").getClass());
322 addNecessaryInstanceMethod(c, "<init>", "()V");
323 } catch (java.io.UnsupportedEncodingException x) { }
324
325
326 c = (jq_Class) addNecessaryType("Lsun/nio/cs/ISO_8859_1;");
327 addNecessaryInstanceMethod(c, "<init>", "()V");
328
329 addNecessaryType("Lsun/nio/cs/ISO_8859_1$Encoder;");
330 addNecessaryType("Lsun/nio/cs/ISO_8859_1$Decoder;");
331 addNecessaryType("Lsun/nio/cs/ISO_8859_1$1;");
332
333
334 addNecessaryType("Lsun/net/www/protocol/jar/Handler;");
335 addNecessaryType("Ljava/util/logging/LogManager$Cleaner;");
336
337
338
339
340
341 }
342
343 public boolean addObjectAndSubfields(Object o) {
344 return addObjectAndSubfields(o, visitedObjects);
345 }
346 private boolean addObjectAndSubfields(Object o, LinkedHashSet objs) {
347 if (o == null) return false;
348 IdentityHashCodeWrapper a = IdentityHashCodeWrapper.create(o);
349 if (visitedObjects.contains(a) || objs.contains(a))
350 return false;
351 objs.add(a);
352 Class objType = o.getClass();
353 jq_Reference jqType = (jq_Reference)Reflection.getJQType(objType);
354 if (TRACE) out.println("Adding object of type "+jqType+": "+o);
355 addInstantiatedType(jqType);
356
357
358
359
360
361 if (jqType.isArrayType()) {
362 jq_Type elemType = ((jq_Array)jqType).getElementType();
363 if (elemType.isAddressType()) {
364
365 } else if (elemType.isReferenceType()) {
366 int length = java.lang.reflect.Array.getLength(o);
367 Object[] v = (Object[])o;
368 if (TRACE) out.println("Visiting "+jqType+" of "+length+" elements");
369 for (int k=0; k<length; ++k) {
370 Object o2 = Reflection.arrayload_A(v, k);
371 addObjectAndSubfields(o2, objs);
372 }
373 }
374 } else {
375 Assert._assert(jqType.isClassType());
376 jq_Class clazz = (jq_Class)jqType;
377 jq_InstanceField[] fields = clazz.getInstanceFields();
378 for (int k=0; k<fields.length; ++k) {
379 jq_InstanceField f = fields[k];
380 if (!AddAllFields && !necessaryFields.contains(f))
381 continue;
382 jq_Type ftype = f.getType();
383 if (ftype.isAddressType()) {
384
385 } else if (ftype.isReferenceType()) {
386 if (TRACE) out.println("Visiting field "+f);
387 Object o2 = Reflection.getfield_A(o, f);
388 addObjectAndSubfields(o2, objs);
389 }
390 }
391 }
392 return true;
393 }
394
395 public void addNecessarySubfieldsOfVisitedObjects() {
396 if (AddAllFields) return;
397 LinkedHashSet objs = visitedObjects;
398 for (;;) {
399 LinkedHashSet objs2 = new LinkedHashSet();
400 boolean change = false;
401 for (Iterator i = objs.iterator(); i.hasNext(); ) {
402 Object o = ((IdentityHashCodeWrapper)i.next()).getObject();
403 Class objType = o.getClass();
404 jq_Reference jqType = (jq_Reference)Reflection.getJQType(objType);
405 if (jqType.isArrayType()) continue;
406 Assert._assert(jqType.isClassType());
407 jq_Class clazz = (jq_Class)jqType;
408 jq_InstanceField[] fields = clazz.getInstanceFields();
409 for (int k=0; k<fields.length; ++k) {
410 jq_InstanceField f = fields[k];
411 if (!necessaryFields.contains(f))
412 continue;
413 jq_Type ftype = f.getType();
414 if (ftype.isAddressType()) {
415
416 } else if (ftype.isReferenceType()) {
417 if (TRACE) out.println("Visiting field "+f+" of object of type "+clazz);
418 Object o2 = Reflection.getfield_A(o, f);
419 if (addObjectAndSubfields(o2, objs2))
420 change = true;
421 }
422 }
423 }
424 if (!change) break;
425 if (TRACE) out.println("Objects added: "+objs2.size()+", iterating over those objects.");
426 visitedObjects.addAll(objs2);
427 objs = objs2;
428 }
429 }
430
431 public void addAllInterfaceMethodImplementations(jq_InstanceMethod i_m) {
432 addNecessaryMethod(i_m);
433 jq_Class interf = i_m.getDeclaringClass();
434 Assert._assert(interf.isInterface());
435 Iterator i = necessaryTypes.iterator();
436 while (i.hasNext()) {
437 jq_Type t = (jq_Type)i.next();
438 if (!t.isReferenceType()) continue;
439 if (t.isAddressType()) continue;
440 jq_Reference r = (jq_Reference)t;
441 if (!r.implementsInterface(interf)) continue;
442 jq_InstanceMethod m2 = r.getVirtualMethod(i_m.getNameAndDesc());
443 if (m2 == null) {
444
445 if (TRACE) out.println("Error: class "+r+" does not implement interface method "+i_m);
446 continue;
447 }
448 addNecessaryMethod(m2);
449 }
450 }
451
452 public void addAllVirtualMethodImplementations(jq_InstanceMethod i_m) {
453 addNecessaryMethod(i_m);
454 addAllVirtualMethodImplementations(i_m.getDeclaringClass(), i_m);
455 }
456
457 public void addAllVirtualMethodImplementations(jq_Class c, jq_InstanceMethod i_m) {
458 if (!i_m.isOverridden())
459 return;
460 jq_Class[] subclasses = c.getSubClasses();
461 for (int i=0; i<subclasses.length; ++i) {
462 jq_Class subclass = subclasses[i];
463 subclass.prepare();
464 jq_Method m2 = (jq_Method)subclass.getDeclaredMember(i_m.getNameAndDesc());
465 if (m2 != null && !m2.isStatic()) {
466 addNecessaryMethod(m2);
467 }
468 addAllVirtualMethodImplementations(subclass, i_m);
469 }
470 }
471
472
473 public void trimClass(jq_Class clazz) {
474 Assert._assert(clazz.isPrepared());
475
476 jq_Class super_class = clazz.getSuperclass();
477 if (super_class != null)
478 trimClass(super_class);
479
480
481 Set necessaryFields = getNecessaryFields();
482 Set necessaryMethods = getNecessaryMethods();
483
484 Iterator it = clazz.getMembers().iterator();
485 while (it.hasNext()) {
486 jq_Member m = (jq_Member)it.next();
487 if (m instanceof jq_Field) {
488 if (!necessaryFields.contains(m)) {
489 if (TRACE) out.println("Eliminating field: "+m);
490 it.remove();
491 }
492 } else {
493 Assert._assert(m instanceof jq_Method);
494 if (!necessaryMethods.contains(m)) {
495 if (TRACE) out.println("Eliminating method: "+m);
496 it.remove();
497 }
498 }
499 }
500
501 int n;
502 n=0;
503 jq_InstanceField[] declared_instance_fields = clazz.getDeclaredInstanceFields();
504 for (int i=0; i<declared_instance_fields.length; ++i) {
505 jq_InstanceField f = declared_instance_fields[i];
506 f.unprepare();
507 if (necessaryMethods.contains(f)) ++n;
508 }
509 jq_InstanceField[] ifs = new jq_InstanceField[n];
510 for (int i=0, j=-1; j<n-1; ++i) {
511 jq_InstanceField f = declared_instance_fields[i];
512 if (necessaryFields.contains(f)) {
513 ifs[++j] = f;
514 ++jq_Class.NumOfIFieldsKept;
515 } else {
516 if (TRACE) out.println("Eliminating instance field: "+f);
517 ++jq_Class.NumOfIFieldsEliminated;
518 }
519 }
520 clazz.setDeclaredInstanceFields(ifs);
521
522 jq_StaticField[] static_fields = clazz.getDeclaredStaticFields();
523 int static_data_size=0;
524 n=0;
525 for (int i=0; i<static_fields.length; ++i) {
526 jq_StaticField f = static_fields[i];
527 f.unprepare();
528 if (necessaryFields.contains(f)) ++n;
529 }
530 jq_StaticField[] sfs = new jq_StaticField[n];
531 for (int i=0, j=-1; j<n-1; ++i) {
532 jq_StaticField f = static_fields[i];
533 if (necessaryFields.contains(f)) {
534 sfs[++j] = f;
535 static_data_size += f.getWidth();
536 ++jq_Class.NumOfSFieldsKept;
537 }
538 else {
539 if (TRACE) out.println("Eliminating static field: "+f);
540 ++jq_Class.NumOfSFieldsEliminated;
541 }
542 }
543 clazz.setDeclaredStaticFields(sfs);
544
545 n=0;
546 jq_InstanceMethod[] declared_instance_methods = clazz.getDeclaredInstanceMethods();
547 for (int i=0; i<declared_instance_methods.length; ++i) {
548 jq_InstanceMethod f = declared_instance_methods[i];
549 f.unprepare();
550 f.clearOverrideFlags();
551 if (necessaryMethods.contains(f)) ++n;
552 }
553 jq_InstanceMethod[] ims = new jq_InstanceMethod[n];
554 for (int i=0, j=-1; j<n-1; ++i) {
555 jq_InstanceMethod f = declared_instance_methods[i];
556 if (necessaryMethods.contains(f)) {
557 ims[++j] = f;
558 ++jq_Class.NumOfIMethodsKept;
559 } else {
560 if (BootstrapRootSet.TRACE) BootstrapRootSet.out.println("Eliminating instance method: "+f);
561 ++jq_Class.NumOfIMethodsEliminated;
562 }
563 }
564 clazz.setDeclaredInstanceMethods(ims);
565
566 n=0;
567 jq_StaticMethod[] static_methods = clazz.getDeclaredStaticMethods();
568 for (int i=0; i<static_methods.length; ++i) {
569 jq_StaticMethod f = static_methods[i];
570 f.unprepare();
571 if (necessaryMethods.contains(f)) ++n;
572 }
573 jq_StaticMethod[] sms = new jq_StaticMethod[n];
574 for (int i=0, j=-1; j<n-1; ++i) {
575 jq_StaticMethod f = static_methods[i];
576 if (necessaryMethods.contains(f)) {
577 sms[++j] = f;
578 ++jq_Class.NumOfSMethodsKept;
579 } else {
580 if (BootstrapRootSet.TRACE) BootstrapRootSet.out.println("Eliminating static method: "+f);
581 ++jq_Class.NumOfSMethodsEliminated;
582 }
583 }
584 clazz.setDeclaredStaticMethods(sms);
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603 clazz.getCP().trim(necessaryFields, necessaryMethods);
604
605 clazz.prepare();
606 }
607 }